/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/

#include <unistd.h>

#include "wx/wx.h"

#include "owndebug.h"
#include "ownutils.h"


//#include "SimWindow.h"
#include "SimFrame.h"
#include "SimFrame2.h"
#include "ode/ode.h"
#include "MLMA.h"
#include "World.h"

void* threadFunc(void *p)
{
  CWorld *world=(CWorld*)p;

  double start, diff, step, speed;
  int sleepTime=1;

  while (true)
  {
    start=ownTime_get_s();
    step=world->GetStepSize();

    world->Step(); //simulate

    diff=ownTime_get_s_since(start);
    speed=step/diff;

    if (diff<step)
    {
      sleepTime=(int)(1000.0*(step-diff));
      speed=1.0;
    } else {
      sleepTime=1;
    }

    ownSleep_ms(sleepTime);
  }
}

void startWithoutGraphics(int stepSize, bool quick, const char* fileName, 
    bool useGimiSettingsFile, std::string gimiSettingsFile,
    std::string hub, int port)
{
  dPrint(1,"Running without graphics");
  CWorld *world=MLMALoadWorld(fileName);

  if (!world)
    return;

  if (useGimiSettingsFile) {
    world->SetGimiSettingsFile(gimiSettingsFile);
  } else {
    world->SetHub(hub,port);
  }
  
  world->SetStepSize(stepSize/1000.0);
  world->SetQuickMode(quick);
  world->Activate();

  ownThread_Create((void*)threadFunc, world);

}

void printHelp()
{
  printf("Possible command line params for FSRSim:\n");
  printf("<world file name> - World file to load\n"); 
  printf("-v <level> - set debug level\n");
  printf("-s <step size> - set step size in milliseconds\n");
  printf("-q - quick mode\n");
  printf("-x - disable graphics\n");
  printf("-L <file name> - log target file\n");
  printf("-f <conf_file> - Use 'conf_file' as configuration file, or optionally use following parameters:\n");
  printf("-u <addr> - Use 'addr' as GIMnet AccessPoint address\n");
  printf("-p <port> - Use 'port' as GIMnet AccessPoint port\n");
}

class MainApp : public wxApp
{
public:
  virtual bool OnInit();
};

IMPLEMENT_APP(MainApp)

bool MainApp::OnInit()
{
  dInitODE();
  debugInit();

  bool parse=true;
  int option;
  int debuglevel=1;
  int stepsize_ms=20;
  int simmode=1;
  std::string logfile="log.txt";
  std::string simfile;
  std::string gimiSettingsFile="gimi_settings.xml";
  std::string hubAddress="";
  int hubPort=-1;
  bool useGimiSettingsFile=true;
  bool simfileSet=false;
  bool graphics=true;

  printf("\nFSRSim\n\n");

  while (parse)
  {
    option=getopt(argc,argv,"v:s:L:qxhf:u:p:");
    switch (option)
    {
      case 'v':
        if (optarg != NULL)
          debuglevel=atoi(optarg);
        break;
      case 's':
        if (optarg != NULL)
          stepsize_ms=atoi(optarg);
        break;
      case 'q':
        simmode=-1;
        break;
      case 'L':
        if (optarg != NULL)
          logfile = optarg;
        break;
      case 'x':
        graphics = false;
        break;
      case 'h':
        printHelp();
        exit(TRUE);
        break;
      case 'f':
        if (optarg != NULL)
        {
          useGimiSettingsFile=true;
          gimiSettingsFile = optarg;
        }
        break;
      case 'u':
        if (optarg != NULL)
        {
          useGimiSettingsFile=false;
          hubAddress= optarg;
        }
        break;
      case 'p':
        if (optarg != NULL)
        {
          useGimiSettingsFile=false;
          hubPort= atoi(optarg);
        }
        break;
      case -1:
        parse = false;
        break;
    }
  }
  if (optind < argc)
  {
    simfile=argv[optind];
    simfileSet=true;

  }

  debugSetGlobalDebugLvl(debuglevel);
  //debugSetMode(DEBUG_MODE_FORMAT_FILE_FUNC_LINE);
  debugSetLogFilename(logfile.c_str());
  //debugSetLogFilename("log.txt");
  debugAddMode(DEBUG_MODE_IMMEDIATE_FLUSH);

  SimFrame2 *frame=NULL;

  if (graphics)
    frame=new SimFrame2(NULL);

  if (useGimiSettingsFile)
  {
    printf("Using file %s for gimi connection settings.\n",gimiSettingsFile.c_str());
    if (frame)
    frame->SetGimiSettingsFile(gimiSettingsFile);
  } else {
    printf("Using hub %s, port %d as gimi acces point.\n",hubAddress.c_str(),hubPort);
    if (frame)
    frame->SetHub(hubAddress,hubPort);
  }
  
  if (simfileSet)
  {
    bool quick;
    if (simmode==1)
    {
      quick=false;
      dPrint(1,"Opening file %s , using step size of %d ms in normal mode...",simfile.c_str(),stepsize_ms);
    } else {
      quick=true;
      dPrint(1,"Opening file %s , using step size of %d ms in quick mode...",simfile.c_str(),stepsize_ms);
    }

    if (graphics)
    {
      frame->OpenFile(simfile.c_str(),simmode*stepsize_ms);
    } else {
      startWithoutGraphics(stepsize_ms,quick,simfile.c_str(),useGimiSettingsFile, 
                            gimiSettingsFile,hubAddress,hubPort);
      
    }

  }



  //CSimWindow *frame = new CSimWindow();
  //SimFrame *frame= new SimFrame(NULL);
  if (graphics)
    frame->Show(TRUE);

  return TRUE;
}
